<template>
  <a-card>
    <a-table
      v-bind="$attrs"
      ref="tableRef"
      row-key="id"
      :columns="columns"
      :data="props.data"
      :pagination="pagination as PaginationProps"
      :row-selection="props.selection ? selectionOptions : undefined"
      size="medium"
      column-resizable
      :bordered="false"
      :scroll="props.scrollMinWidth ? { minWidth: scrollMinWidth } : undefined"
      :default-expand-all-rows="props.defaultExpandAllRows"
      @select="selectRowRecord"
      @select-all="selectAll"
      @selection-change="selectionChanged"
    >
      <template #empty>
        <a-empty
          :description="props.emptyText ? props.emptyText : '暂无数据'"
        />
      </template>
      <template v-for="(_, name) in $slots" #[name]="slotData">
        <slot :name="name" v-bind="slotData"></slot>
      </template>
    </a-table>
  </a-card>
</template>

<script setup lang="tsx">
  import {
    TableData,
    TableInstance,
    TableRowSelection,
    PaginationProps,
    Tag,
  } from '@arco-design/web-vue';
  import dayjs from 'dayjs';
  import { UnwrapRef } from 'vue';

  import { useDictStore } from '@/store';

  const dictStore = useDictStore();

  type selectionType = 'checkbox' | 'radio';

  interface TableType {
    columns: UnwrapRef<TableColumn[]>;
    data?: TableData[];
    pagination: UnwrapRef<Pagination> | boolean;
    selection?: selectionType;
    selectAll?: boolean;
    maxSelectSize?: number;
    selectedData?: TableData[];
    selectedKeys?: (string | number)[];
    emptyText?: string;
    scrollMinWidth?: number;
    defaultExpandAllRows?: boolean;
  }

  const props = defineProps<TableType>();

  const emits = defineEmits([
    'update:selectedData',
    'update:selectedKeys',
    'register',
  ]);

  const tableRef = ref<TableInstance>();

  // eslint-disable-next-line vue/no-dupe-keys
  const selectedData = ref<TableData[]>([]);

  onMounted(() => {
    emits('register', tableRef.value?.$parent?.$parent, tableRef.value);
  });

  const columns = computed<TableColumn[]>(() => {
    return props.columns.map((item: TableColumn) => {
      if (item.type === 'index') {
        let pageNo: number;
        let pageSize: number;
        if (typeof props.pagination === 'boolean') {
          pageNo = 1;
          pageSize = 10;
        } else {
          pageNo = props.pagination?.current ?? 1;
          pageSize = props.pagination?.pageSize ?? 10;
        }
        item.render = (data: TableData) => {
          return h('span', {}, data.rowIndex + 1 + (pageNo - 1) * pageSize);
        };
        item.width = 100;
      } else if (item.type === 'date') {
        item.render = (data: TableData) => {
          if (data.record[item.field]) {
            return <>{dayjs(data.record[item.field]).format('YYYY-MM-DD')}</>;
          }
        };
      } else if (item.type === 'enumTag') {
        item.render = (data: TableData) => {
          const label = dictStore.getLabel(
            item.enumName || '',
            data.record[item.field]
          );
          return (
            <>
              {label && (
                <Tag color={getTagColor(data.record[item.field])}>{label}</Tag>
              )}
            </>
          );
        };
      } else if (item.type === 'editor') {
        item.render = (data: TableData) => {
          return <>{replaceHtml(data.record[item.field])}</>;
        };
      } else if (item.field === 'action') {
        return {
          width: 200,
          ...item,
          title: item.title,
          dataIndex: item.field || item.dataIndex,
        };
      }
      return {
        ellipsis: true,
        tooltip: true,
        ...item,
        title: item.title,
        dataIndex: item.field || item.dataIndex,
      };
    });
  });

  const selectionOptions = computed<TableRowSelection>(() => {
    return {
      type: props.selection === 'checkbox' ? 'checkbox' : 'radio',
      showCheckedAll: props.selection === 'checkbox' && props.selectAll,
      selectedRowKeys: props.selectedKeys,
    };
  });

  const selectionChanged = (rowKes: (string | number)[]) => {
    if (props.maxSelectSize && rowKes.length > props.maxSelectSize) {
      return;
    }
    selectionOptions.value.selectedRowKeys = rowKes;
    emits('update:selectedKeys', rowKes);
  };

  const selectAll = (checked: boolean) => {
    if (checked) {
      props.data?.forEach((item) => {
        if (!item.disabled) {
          selectedData.value.push(item);
        }
      });
    } else {
      selectedData.value = selectedData.value.filter((item: TableData) => {
        return !props.data?.map((ele) => ele.id).includes(item.id);
      });
    }
    emits('update:selectedData', selectedData.value);
  };

  const selectRowRecord = (
    rowKeys: (string | number)[],
    rowKey: string | number,
    record: TableData
  ) => {
    if (props.selection === 'checkbox') {
      if (rowKeys.includes(rowKey)) {
        if (
          selectionOptions.value.selectedRowKeys &&
          props.maxSelectSize &&
          selectionOptions.value.selectedRowKeys.length >= props.maxSelectSize
        ) {
          MessageInfo.warning(`最多可以选择${props.maxSelectSize}项`);
          return false;
        }
        selectedData.value?.push(record);
      } else {
        selectedData.value?.forEach((item: TableData, index: number) => {
          if (item.id === rowKey) {
            selectedData.value?.splice(index, 1);
          }
        });
      }
    } else {
      selectedData.value = [record];
    }
    emits('update:selectedData', selectedData.value);
  };

  const replaceHtml = (str: string | null | undefined) => {
    if (!str) {
      return str;
    }
    str = str.replace(/<[^>]+>|&[^>]+;/g, '').trim(); // 去掉所有的html标签和&nbsp;之类的特殊符合
    return str;
  };

  const getSelectionData = () => {
    if (!selectedData.value.length) {
      MessageInfo.warning('请选择数据');
      return;
    }
    return selectedData.value;
  };

  const getSelectionDataKey = () => {
    if (!selectedData.value.length) {
      MessageInfo.warning('请选择数据');
      return;
    }
    return selectionOptions.value.selectedRowKeys;
  };

  const getTagColor = (val: number) => {
    if (val === 1) {
      return 'green';
    } else if (val === 2) {
      return 'red';
    } else if (val === 3) {
      return 'orange';
    } else if (val === 4) {
      return 'purple';
    } else {
      return 'blue';
    }
  };

  defineExpose({ getSelectionData, getSelectionDataKey, tableRef });
</script>
